/*
 * Copyright 2018- The Pixie Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

syntax = "proto3";

package px.carnot.planner.distributedpb;

option go_package = "distributedpb";

import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "src/api/proto/uuidpb/uuid.proto";
import "src/carnot/planpb/plan.proto";
import "src/common/base/statuspb/status.proto";
import "src/shared/bloomfilterpb/bloomfilter.proto";
import "src/shared/metadatapb/metadata.proto";
import "src/table_store/schemapb/schema.proto";

// Info about the Metadata stored on a Carnot instance.
message MetadataInfo {
  // A list of the metadata fields that are stored in MetadataInfo.
  // If we don't store a particular field in metadata_fields, the compiler shouldn't
  // use it for pruning query plans.
  repeated px.shared.metadatapb.MetadataType metadata_fields = 1;
  // A structure such as a bloom filter, that contains all of the values
  // for the carnot's metadata, such as container id, service name, pod id, namespace.
  // This structure may contain false positives but not false negatives.
  oneof filter {
    px.shared.bloomfilterpb.XXHash64BloomFilter xxhash64_bloom_filter = 2
        [ (gogoproto.customname) = "XXHash64BloomFilter" ];
  }
}

// Info about the Distributed characteristics of a Carnot instance.
message CarnotInfo {
  // The unique address used by the query broker to contact this instance.
  string query_broker_address = 1;
  // The unique ID of this agent.
  uuidpb.UUID agent_id = 10 [ (gogoproto.customname) = "AgentID" ];
  // Flag if the Carnot instance hosts a GRPC server.
  bool has_grpc_server = 2 [ (gogoproto.customname) = "HasGRPCServer" ];
  // The address of the GRPC server hosted by the Carnot instance, it has a GRPC
  // server.
  string grpc_address = 3 [ (gogoproto.customname) = "GRPCAddress" ];
  // Flag if the carnot instance has an in-memory store of data.
  // E.g. agents stores data, but some Kelvin instances might only be used for
  // computation.
  bool has_data_store = 4;
  // Flag whether this Carnot instance can process data.
  // E.g. the query broker only wants to accept data and pass it up to the UI.
  bool processes_data = 5;
  // Flag if this Carnot instance accepts remote sources.
  // E.g. Kelvin instances accept remote sources - they are arbitrary workers,
  // agents are not.
  bool accepts_remote_sources = 6;
  // Info about the tables for the Carnot instance.
  repeated TableInfo table_info = 7;
  // The asid of the Agent running the Carnot.
  uint32 asid = 8 [ (gogoproto.customname) = "ASID" ];
  // Information about the metadata stored on a Carnot instance.
  MetadataInfo metadata_info = 9;
  // Optional field that gives the SSL target hostname for this Carnot instance.
  string ssl_targetname = 11 [ (gogoproto.customname) = "SSLTargetName" ];
}

// Information about the table structure as well as the tablet keys.
message TableInfo {
  // The table that is associated with the tablets.
  string table = 1;
  // The tabletization key of the table.
  string tabletization_key = 2;
  // The tablet values to use.
  repeated string tablets = 3;
}

// SchemaInfo maps the available schemas in Vizier to the agents that can
// actually use them. We use inverted mapping to save space, especially on large
// clusters where we might have many entries for CarnotInfo::TableInfo.
message SchemaInfo {
  // The name of the table.
  string name = 1;
  // The relation for the table.
  px.table_store.schemapb.Relation relation = 2;
  // The list of agents that hold this schema.
  repeated uuidpb.UUID agent_list = 3;
}

// The Distributed state of the distributed Carnot instances.
message DistributedState {
  // Info about all available Carnot instances in Vizier.
  repeated CarnotInfo carnot_info = 1;
  // Schemas definitions and which agents hold tables corresponding to those
  // schemas.
  repeated SchemaInfo schema_info = 2;
}

// The Distributed Plan message that describes the graph of the plans
// and which plans should execute on each Carnot instance.
message DistributedPlan {
  // Map query broker address of Carnot instance to the Plan it will execute.
  map<string, px.carnot.planpb.Plan> qb_address_to_plan = 1;
  // Map from query broker address to the id used in the dag.
  map<string, uint64> qb_address_to_dag_id = 2;
  // The DAG describing the connections between the Distributed nodes.
  px.carnot.planpb.DAG dag = 3;
}

// RedactionOptions message specifies how to redact sensitive columns.
message RedactionOptions {
  // Fully redact all sensitive columns. If this is true, all other redaction options are ignored.
  bool use_full_redaction = 1;
  // Redact sensitive columns by calling px.redact_pii_best_effort on them.
  bool use_px_redact_pii_best_effort = 2;
}

// OTelEndpointConfig contains the connection parameters for an OpenTelemetry
// Exporter.
message OTelEndpointConfig {
  // url is the address of the OpenTelemetry collector.
  string url = 1 [ (gogoproto.customname) = "URL" ];
  // The headers that should be attached to the connection context, such as
  // authentication credentials or api keys.
  map<string, string> headers = 2;
  // True if the OpenTelemetry collector is not protected with SSL.
  bool insecure = 3;
  // The amount of time in seconds before the request to the OTel collector should timeout. Default:
  // 5s.
  int64 timeout = 4;
}

message PluginConfig {
  // The start_time of the script in nanoseconds.
  int64 start_time_ns = 1;
  // The end_time of the script in nanoseconds.
  int64 end_time_ns = 2;
}

message DebugInfo {
  message OTelDebugAttribute {
    string name = 1;
    string value = 2;
  }

  repeated OTelDebugAttribute otel_debug_attributes = 1;
}
// LogicalPlannerState contains the information necessary to create the Logical
// Plan. This message is used by the query broker to send to the logical
// planner.
message LogicalPlannerState {
  reserved 1, 6;
  // The distributed state of all Carnot instances in the system.
  DistributedState distributed_state = 2;
  // The query options for how the plans should be executed.
  px.carnot.planpb.PlanOptions plan_options = 3;
  // The address to which the query results should be sent.
  string result_address = 4;
  // The SSL target override for the result address, if applicable.
  string result_ssl_targetname = 5 [ (gogoproto.customname) = "ResultSSLTargetName" ];
  // RedactionOptions specifies whether redaction should be done, and how to do it.
  // If redaction_options is nil, then no redaction is done.
  RedactionOptions redaction_options = 7;

  // OTelEndpointconfig configures the default endpoint config for all plans compiled
  // with this logical planner state. Any plans that don't manually specify a config will
  // use this one. If this config is not specified and the plan fails to specify an endpoint
  // config for otel configurations, that plan compilation will fail.
  OTelEndpointConfig otel_endpoint_config = 8 [ (gogoproto.customname) = "OTelEndpointConfig" ];

  // PluginConfig contains plugin related configuration.
  PluginConfig plugin_config = 9;

  // Debug options for the compiler.
  DebugInfo debug_info = 10;
}

// The result for the planner. Contains a status to track any errors
message LogicalPlannerResult {
  px.statuspb.Status status = 1;
  DistributedPlan plan = 2;
}
